<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>树形数据结构与扁平数据结构</title>
</head>
<body>
  <script>
    const data = [
      {
        id: 2,
        pid: 0,
        path: '/course',
        name: 'Course',
        title:'课程管理',
        children: [
          {
            id: 3,
            pid: 2, // parentId
            path: '/course',
            name: 'Course',
            title:'课程操作',
            children: [
              {
                id: 4,
                pid: 3,
                path: '/course',
                name: 'Course',
                title:'课程数据'
              },
            ]
          },
          {
            id: 5,
            pid: 2,
            path: '/course',
            name: 'Course',
            title:'增加爱课程'
          },
        ]
      },
      {
        id: 6,
        pid: 0,
        path: '/course',
        name: 'Course',
        title:'学生管理',
        children: [
          {
            id: 7,
            pid: 6,
            path: '/course',
            name: 'Course',
            title:'学生操作'
          },
          {
            id: 8,
            pid: 6,
            path: '/course',
            name: 'Course',
            title:'增加学生'
          }
        ]
      }
    ]

    console.log(flat(data))

    function flat(arr) {
      var newArr = [] // 新数组
      for (var i=0;i<arr.length;i++) {
        if(arr[i].children) { // children存在
          newArr.push(...flat(arr[i].children)) // 递归，调用flat方法，并将返回结果push到新数组
          delete arr[i].children // 删除原有children属性
        }
        newArr.push({...arr[i]})
      }
      return newArr;
    }

    // 树形转扁平思路 ( 递归方法 )：
    // 1、循环数组，取出每个对象进行判断
    // 2、如果有children属性，将children传到flat函数重复执行，并将执行的结构返回数组，加入到新数组中。然后删除当前对象的children属性
    // 3、不管是否有children属性，都要将当前对象解构，然后加入新数组中
    const flatData = [
      {
        id: 2,
        pid: 0,
        path: '/course',
        name: 'Course',
        title:'课程管理'
      },
      {
        id: 3,
        pid: 2, // parentId
        path: '/course',
        name: 'Course',
        title:'课程操作'
      },
      {
        id: 4,
        pid: 3,
        path: '/course',
        name: 'Course',
        title:'课程数据'
      },
      {
        id: 5,
        pid: 2,
        path: '/course',
        name: 'Course',
        title:'增加爱课程'
      },
      {
        id: 6,
        pid: 0,
        path: '/course',
        name: 'Course',
        title:'学生管理'
      },
      {
        id: 7,
        pid: 6,
        path: '/course',
        name: 'Course',
        title:'学生操作'
      },
      {
        id: 8,
        pid: 6,
        path: '/course',
        name: 'Course',
        title:'增加学生'
      },
      {
        id: 9,
        pid: 8,
        path: '/course',
        name: 'Course',
        title:'增加学生'
      },{
        id: 10,
        pid: 11,
        path: '/course',
        name: 'Course',
        title:'增加学生'
      }
    ]
    // 扁平转树形
    // 注：使用此方法，要求扁平数据中的id必须进行升序排列
    // 核心思想：Map来存储不同的id，对应的所在的内存地址，根据对应pid的值，找到你要加入到对象对应的位置。
    var TreeData = GetTreeData(flatData);

    console.log(TreeData, 'flatData');

    function GetTreeData(data) {
      var TreeData=[];
      var map = new Map();
      var outputObj, pid;

      for(var i=0;i<data.length;i++) {
        pid = data[i].pid;

        if(map.has(pid)) {
          //存在，将此信息，加入到对应id=pid的对象上的children
          if (!map.get(pid).children) //添加children属性
              map.get(pid).children = [];
          var obj = new Object(data[i]);
          map.get(pid).children.push(obj);
          //通过pid在Map中查找，并将当前对象，加入到对应的childres属性
          map.set(data[i].id, obj);
          //重点(必须也加入Map)：将当前id及对应的对象，存入Map对象中
        } else if (!map.has(pid) && pid == 0) {
          //这里处理pid不存在，且pid为0的处理，pid不存在，且不为0的，程序不考虑这种情况
          outputObj = new Object(data[i]);
          //加入到要返回的数组中
          TreeData.push(outputObj);
          //将id添加到Map中
          map.set(data[i].id, outputObj);
        }
      }
      return TreeData
    }

    // 若pid对应的值，id没有，使用上面的转换方法，将忽略这条数据

  </script>
</body>
</html>